<?php

/**
 * Created By PhpStorm
 * User sclecon
 * Contact Email 27941662@qq.com
 * Time 2021/8/26 15:18
 */


namespace wowo;

class Route
{
    private $dir = 'route';
    protected $routes = [];
    protected $includeFiles = false;
    protected $_get = [];
    protected $_post = [];
    protected $_files = [];

    public function __construct(){
        $this->initParams();
    }

    public function getRequest($rewrite = "", $method = 'GET'){
        $request = [
            'object'        =>  "\app\controller\\".\wowo\instance\Config::get('app.controller'),
            'action'        =>  \wowo\instance\Config::get('app.action'),
            '_get'          =>  []
        ];
        $matchFlag = false;
        $rewrite = $rewrite == '' ? '/' : $rewrite;
        $routes = $this->getRoutes();
        $filters = filterByValue($routes, 'route', $rewrite);
        if ($filters !== false){
            $filters = filterByValue($filters, 'method', ['all', strtolower($method)]);
        }
        $route = is_array($filters) ? end($filters) : false;
        if ($route === false){
            $route = $this->getRoutersTheRewrite($routes, $rewrite, $method);
            if ($route){
                $request['_get'] = $route['_get'];
                $request['object'] = $route['object'];
                $request['action'] = $route['action'];
                $matchFlag = true;
            }
        }else{
            $request['object'] = $route['object'];
            $request['action'] = $route['action'];
            $matchFlag = true;
        }
        if ($matchFlag === false){
            throw new \Exception("Route \"".$rewrite."\" is Not Match");
        }
        return $request;
    }

    public function initParams(){
        $this->_get = $_GET;
        unset($this->_get['id']);
        $this->_post = $_POST;
        $this->_files = $_SERVER['files'];
    }

    public function get($route, $class, $action = ''){
        return $this->rule('get', $route, $class, $action);
    }

    public function post($route, $class, $action = ''){
        return $this->rule('post', $route, $class, $action);
    }

    private function rule($method, $route, $class, $action){
        return $this->routes[] = ['method'=>$method, 'route'=>$route, 'object'=>$class, 'action'=>$action];
    }

    public function getRoutes(){
        if ($this->includeFiles === false){
            $this->loadRule();
        }
        return $this->routes;
    }

    public function getUrl($path, $params = []){
        list($controller, $action) = explode('/', $path);
        $routes = filterByValue($this->routes, 'method', ['get', 'all', 'post']);
        $routes = filterByValue($routes, 'object', 'app\controller\\'.ucfirst($controller));
        $routes = filterByValue($routes, 'action', $action);
        if (is_array($routes) and count($routes)){
            $route = end($routes)['route'];
            preg_match_all('/{(.*)}/U', $route, $response);
            if (count($response[1]) > 0){
                $values = [];
                foreach ($response[1] as $field){
                    $values[] = isset($params[$field]) ? $params[$field] : '';
                    unset($params[$field]);
                }
                $route = str_replace($response[0], $values, $route);
            }
            return \wowo\instance\Config::get('app.siteUrl').'/'.$route.($params ? '?'.http_build_query($params) : '');
        }else{
            return \wowo\instance\Config::get('app.siteUrl').($params ? '?'.http_build_query($params) : '');
        }
    }

    private function loadRule(){
        $dir = app()->appPath.$this->dir;
        if (is_dir($dir) === false){
            return false;
        }
        $files = \wowo\instance\File::getDirFiles($dir);
        if (count($files) === []){
            return false;
        }
        foreach ($files as $file){
            \wowo\instance\File::includeFile($dir, $file);
        }
        $this->includeFiles = true;
        return $this->includeFiles;
    }

    private function getRoutersTheRewrite($routes, $rewrite, $method){
        foreach ($routes as $route){
            if (count(explode('/', $rewrite)) === count(explode('/', $route['route'])) && in_array($route['method'], [strtolower($method), 'all'])){
                preg_match_all('/{(.*)}/U', $route['route'], $response);
                if (count($response[1]) == 0) continue;
                $rule = '/'.str_replace('/', '\/', $route['route']).'/';
                foreach ($response[0] as $_rule){
                    $rule = str_replace($_rule, strpos($_rule, 'id') === false ? '(.*)' : '([1-9][0-9]*){1,3}', $rule);
                }
                preg_match_all($rule, $rewrite, $rewriteResponse);
                if (count($response[1]) === count($rewriteResponse[1]) or count($response[1]) === (count($rewriteResponse)-1)){
                    $route['_get'] = [];
                    foreach ($response[1] as $index => $field){
                        $route['_get'][$field] = $rewriteResponse[1][$index];
                    }
                    return $route;
                }
            }
        }
        return false;
    }
}